using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Threading.Tasks;
using Comteck.Dto.Orders;
using Comteck.Entities.Orders;
using Comteck.Ktt.Services.Infrastructure;
using ExpressMapper.Extensions;

namespace Comteck.Ktt.Services.Orders {
  /// <summary>
  /// 
  /// </summary>
  public class SelfOrgService : BaseKttService, ISelfOrgService {
    private readonly IKttRepository<SelfOrg, int> _SelfOrgRepository;
    private readonly IKttRepository<SelfOrgTagRelation, string> _SelfOrgTagRelationRepository;
    private readonly Lazy<ISaleOrderService> saleOrderService;

    public SelfOrgService(IKttUnitOfWork unitOfWork,
      Lazy<ISaleOrderService> saleOrderService) : base(unitOfWork) {
      _SelfOrgRepository = _unitOfWork.GetRepository<SelfOrg, int>();
      _SelfOrgTagRelationRepository = _unitOfWork.GetRepository<SelfOrgTagRelation, string>();
      this.saleOrderService = saleOrderService;
    }

    /// <summary>
    /// 查询分页主表数据
    /// </summary>
    /// <param name="model"></param>
    /// <returns></returns>
    public async Task<List<SelfOrgDto>> GetListAsync(SelfOrgQuery model) {
      var query = from d in _SelfOrgRepository.TableUntracked
                  select d;
      query = query
        .WhereIIf(model.Name.IsNotNullOrEmpty(), x => x.Name.Contains(model.Name))
        .WhereIIf(model.Contacts.IsNotNullOrEmpty(), x => x.Contacts.Contains(model.Contacts))
        .WhereIIf(model.Phone.IsNotNullOrEmpty(), x => x.Phone.Contains(model.Phone));

      // 标签
      if (model.TagId > 0) {
        query = from d in query
                where (from m in _SelfOrgTagRelationRepository.Table
                       where m.SelfOrgId == d.Id
                         && m.TagId == model.TagId
                       select m).Any()
                select d;
      }

      var list = await query.OrderBy(x => x.Id).ToListAsync();
      var result = list.MapTo<List<SelfOrgDto>>();
      if (result.IsNullOrEmpty()) {
        return result;
      }

      // 查询关联标签
      var selfOrgIdList = result.Select(x => x.Id).ToList();
      var relationDic = (await _SelfOrgTagRelationRepository.FindAsync(x => selfOrgIdList.Contains(x.SelfOrgId))).ToLookup(x => x.SelfOrgId);
      result.ForEach(x => {
        x.TagIds = relationDic[x.Id].Select(y => y.TagId).JoinAsString(",");
      });
      return result;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="selfOrgId"></param>
    /// <returns></returns>
    private async Task<IEnumerable<SelfOrgTagRelation>> GetRelationListAsync(int selfOrgId) {
      return await _SelfOrgTagRelationRepository.FindAsync(x => x.SelfOrgId == selfOrgId);
    }

    /// <summary>
    /// 查询分页主表数据
    /// </summary>
    /// <param name="model"></param>
    /// <returns></returns>
    public async Task<IEnumerable<SelfOrgDto>> GetAllAsync() {
      var list = await _SelfOrgRepository.GetAllAsync();
      return list.MapTo<IEnumerable<SelfOrgDto>>();
    }

    /// <summary>
    /// 查询分页主表数据
    /// </summary>
    /// <param name="model"></param>
    /// <returns></returns>
    public async Task<IEnumerable<SelfOrgTagRelationDto>> GetAllRelationAsync() {
      var list = await _SelfOrgTagRelationRepository.GetAllAsync();
      return list.MapTo<IEnumerable<SelfOrgTagRelationDto>>();

    }

    /// <summary>
    /// 查询分页主表数据
    /// </summary>
    /// <param name="model"></param>
    /// <returns></returns>
    public async Task<IEnumerable<SelfOrgDto>> GetListByIdsAsync(List<int> ids) {
      var list = await _SelfOrgRepository.TableUntracked.Where(x => ids.Contains(x.Id)).ToListAsync();
      return list.MapTo<List<SelfOrgDto>>();
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public async Task<SelfOrgDto> GetEditModelAsync(int id) {
      SelfOrgDto model;
      if (id <= 0) {
        model = new SelfOrgDto();
      } else {
        var entity = await _SelfOrgRepository.GetByIdAsync(id);
        model = entity.MapTo<SelfOrgDto>();
        model.TagIds = (await this.GetRelationListAsync(model.Id)).JoinAsString(",");
      }

      return model;
    }

    /// <summary>
    /// 新增
    /// </summary>
    /// <param name="model"></param>
    /// <returns></returns>
    public async Task<AjaxResponse<SelfOrgDto>> SaveAsync(SelfOrgDto model) {
      var result = new AjaxResponse<SelfOrgDto>() {
        Code = 0
      };

      try {
        // check
        await this.CheckSaveAsync(model);

        _unitOfWork.BeginTransaction();
        var dbEntity = await _SelfOrgRepository.GetByIdAsync(model.Id);

        if (dbEntity == null) {
          // add
          dbEntity = model.MapTo<SelfOrg>();
          dbEntity.CreateTime = DateTime.Now;
          await _SelfOrgRepository.AddAsync(dbEntity);
        } else {
          // modify
          model.MapTo(dbEntity);
          await _SelfOrgRepository.UpdateAsync(dbEntity);
        }

        // 关系
        var relationList = await this.GetRelationListAsync(dbEntity.Id);
        await _SelfOrgTagRelationRepository.RemoveRangeAsync(relationList);

        if (model.TagIds.IsNotNullOrEmpty()) {
          relationList = model.TagIds.SplitSafe(",").Select(x => new SelfOrgTagRelation() {
            Id = Guid.NewGuid().ToString(),
            SelfOrgId = dbEntity.Id,
            TagId = Convert.ToInt32(x)
          });
          await _SelfOrgTagRelationRepository.AddRangeAsync(relationList);
        }

        await _unitOfWork.CommitTransactionAsync();
        result.Code = 1;
        result.Data = dbEntity.MapTo<SelfOrgDto>();
      } catch (Exception ex) {
        _unitOfWork.RollbackTransaction();
        result.Message = ex.Message;
      }

      return result;
    }

    /// <summary>
    /// 校验合法性
    /// </summary>
    /// <param name="model"></param>
    private async Task CheckSaveAsync(SelfOrgDto model) {
      if (model.Name.IsNullOrEmpty()) {
        throw new ComteckException("名称不能为空");
      }

      // 一个用户可以多个分公司，一个分公司只能一个用户
      if (await _SelfOrgRepository.CountAsync(x => x.Id != model.Id && x.Name == model.Name) > 0) {
        throw new ComteckException($"名称 {model.Name} 已存在");
      }
    }

    /// <summary>
    /// 批量新增
    /// </summary>
    /// <param name="list"></param>
    /// <returns></returns>
    public async Task<IEnumerable<SelfOrg>> InsertBatchAsync(IEnumerable<SelfOrg> list) {
      await _SelfOrgRepository.AddRangeAsync(list);
      return list;
    }

    /// <summary>
    /// 新增
    /// </summary>
    /// <param name="model"></param>
    /// <returns></returns>
    public async Task DeleteAsync(int id) {
      var entity = await _SelfOrgRepository.GetByIdAsync(id);
      if (entity == null) {
        throw new ComteckException("自提点不存在");
      }

      if (await saleOrderService.Value.IsSelfOrgUsedAsync(entity.Id)) {
        throw new ComteckException("自提点已经被使用");
      }

      // delete
      try {
        _unitOfWork.BeginTransaction();
        await _SelfOrgRepository.RemoveAsync(entity);
        var relationList = await this.GetRelationListAsync(entity.Id);
        await _SelfOrgTagRelationRepository.RemoveRangeAsync(relationList);
        await _unitOfWork.CommitTransactionAsync();
      } catch {
        _unitOfWork.RollbackTransaction();
        throw;
      }
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="tagId"></param>
    /// <returns></returns>
    public async Task<bool> IsTagUsedAsync(int tagId) {
      return await _SelfOrgTagRelationRepository.AnyAsync(x => x.TagId == tagId);
    }

    /// <summary>
    /// 批量更新
    /// </summary>
    /// <param name="list"></param>
    /// <returns></returns>
    public async Task SaveBatchAsync(IEnumerable<SelfOrgDto> list) {
      if (list.IsNullOrEmpty()) {
        return;
      }

      var dbList = new List<SelfOrg>();
      var relationList = new List<SelfOrgTagRelation>();
      foreach (var item in list) {
        dbList.Add(item.MapTo<SelfOrg>());

        relationList.AddRange(item.TagIds.SplitSafe(",").Select(x => new SelfOrgTagRelation() {
          Id = Guid.NewGuid().ToString(),
          SelfOrgId = item.Id,
          TagId = Convert.ToInt32(x)
        }));
      }

      try {
        _unitOfWork.BeginTransaction();
        await _SelfOrgRepository.UpdateRangeAsync(dbList);
        await _SelfOrgTagRelationRepository.AddRangeAsync(relationList);
        await _unitOfWork.CommitTransactionAsync();
      } catch {
        _unitOfWork.RollbackTransaction();
        throw;
      }
    }
  }
}
